function Graph(obj) {
	this.obj = obj
	this.max = 0
	this.min = 0
	this.count = 0
	this.series = new Array()
	this.labels = new Array()
}

function addSeries(series) {
	this.series[this.series.length++] = series.clone(true)
	this.count = this.countPoints()
	this.max = this.maxValue()
	this.min = this.minValue()
	return this.series.length-1
}
Graph.prototype.addSeries = addSeries

function noTransformX(x) {
	return x
}
Graph.prototype.noTransformX = noTransformX

function noTransformY(y) {
	return y
}
Graph.prototype.noTransformY = noTransformY

function maxValue(stacked,transformX,transformY) {
	transformX = (transformX) ? transformX : this.noTransformX
	transformY = (transformY) ? transformY : this.noTransformY
	
	var max = -9999999
	if (!stacked) {
		for (var s in this.series) {
			if (typeof this.series[s] != "function")
			for (var ss in this.series[s]) {
				if (typeof this.series[s][ss] != "function")
					max = Math.max(max,transformY(this.series[s][transformX(ss)]))
			}
		}
		return max
	} else {
		var sval = this.series.columnAdd()
		//alert (sval)
		return sval.columnMax()[0][0]
	}
}
Graph.prototype.maxValue = maxValue

function minValue(stacked,transformX,transformY) {
	transformX = (transformX) ? transformX : this.noTransformX
	transformY = (transformY) ? transformY : this.noTransformY
	
	var min = 9999999
	if (!stacked) {
		for (var s in this.series) {
			if (typeof this.series[s] != "function")
			for (var ss in this.series[s]) {
				if (typeof this.series[s][ss] != "function")
					min = Math.min(min,this.series[s][ss])
			}
		}
		return min
	} else {
		for (var i = 0; i<this.count; i++) {
			var val = 0
			for (var s in this.series) {
				if (typeof this.series[s] != "function")
						val += this.series[s][i]
			}
			min = Math.min(min,val)
		}
		return min
	}
}
Graph.prototype.minValue = minValue

function countPoints() {
	var count = 0
	for (var s in this.series) {
		if (typeof this.series[s] != "function")
			if (!isNaN(this.series[s].length))
				count = Math.max(count,this.series[s].length)
	}
	return count
}
Graph.prototype.countPoints = countPoints

function drawBoxPlot(color, seriesId,transformX,transformY) {
	transformX = (transformX) ? transformX : this.noTransformX
	transformY = (transformY) ? transformY : this.noTransformY
	
	color = (color) ? color : "blue"
	seriesId = (seriesId) ? seriesId : 0
	var series = this.series[seriesId]

	//this.count = this.countPoints()
	//this.max = this.maxValue(true, transformX, transformY)
	//this.min = this.minValue(false, transformX, transformY)
	
	var heightFactor = this.obj.offsetHeight / this.max
	//alert(this.max)
	var widthFactor = this.obj.offsetWidth / this.count
	var boxWidth = widthFactor * 0.8
	var boxLeftPadding = (widthFactor - boxWidth)/2
	
	var offsetTop = this.obj.offsetTop 
	var offsetLeft = this.obj.offsetLeft
	var pt = this.obj.offsetParent
	while (pt) {
		offsetTop += pt.offsetTop
		offsetLeft += pt.offsetLeft
		pt = pt.offsetParent
	}
	var offsetHeight = this.obj.offsetHeight
	
	for (var i = 0;i<series.length;i++) {
			var height = transformY(series[transformX(i)]) * heightFactor
			var box = document.createElement("div")
			box.style.position = "absolute"
			box.style.left = boxLeftPadding + offsetLeft + (transformX(i) * widthFactor) + "px"
			box.style.height = height + "px"
			box.style.width = boxWidth + "px"
			box.style.top = (offsetTop + offsetHeight - height) + "px"
			box.style.background = color
			box.className="plotBox"
			this.obj.appendChild(box)
	}
}
Graph.prototype.drawBoxPlot = drawBoxPlot

function drawLine(color, seriesId,lineWidth,transformX,transformY) {
	lineWidth = (lineWidth) ? lineWidth : 2
	transformX = (transformX) ? transformX : this.noTransformX
	transformY = (transformY) ? transformY : this.noTransformY
	
	color = (color) ? color : "blue"
	seriesId = (seriesId) ? seriesId : 0
	var series = this.series[seriesId]

	//this.count = this.countPoints()
	//this.max = this.maxValue(false, transformX, transformY)
	//this.min = this.minValue(false, transformX, transformY)
	
	//alert(this.max)
	var heightFactor = this.obj.offsetHeight / this.max
	var widthFactor = this.obj.offsetWidth / this.count
	var boxWidth = widthFactor
	
	var offsetTop = this.obj.offsetTop 
	var offsetLeft = this.obj.offsetLeft
	var pt = this.obj.offsetParent
	while (pt) {
		offsetTop += pt.offsetTop
		offsetLeft += pt.offsetLeft
		pt = pt.offsetParent
	}
	var offsetHeight = this.obj.offsetHeight
	
	for (var i = 0;i<series.length;i++) {
			var height = transformY(series[transformX(i)]) * heightFactor
			//alert(height)
			var box = document.createElement("div")
			box.style.position = "absolute"
			box.style.left = offsetLeft + (transformX(i) * widthFactor) + "px"
			box.style.height = lineWidth + "px"
			box.style.width = boxWidth + "px"
			box.style.top = (offsetTop + offsetHeight - height) + "px"
			box.style.backgroundColor = color
			this.obj.appendChild(box)
	}
}
Graph.prototype.drawLine = drawLine

function clearPlot() {
	while (this.obj.firstChild) {
		this.obj.removeChild(this.obj.firstChild)
	}
}
Graph.prototype.clearPlot = clearPlot

function clearSeries() {
	this.series = new Array()
}
Graph.prototype.clearSeries = clearSeries

function showSeriesLabels(transformX,transformY) {
	transformX = (transformX) ? transformX : this.noTransformX
	transformY = (transformY) ? transformY : this.noTransformY
	
	var heightFactor = this.obj.offsetHeight / this.max
	var widthFactor = this.obj.offsetWidth / this.count
	var boxWidth = widthFactor
	
	var offsetTop = this.obj.offsetTop 
	var offsetLeft = this.obj.offsetLeft
	var pt = this.obj.offsetParent
	while (pt) {
		offsetTop += pt.offsetTop
		offsetLeft += pt.offsetLeft
		pt = pt.offsetParent
	}
	var offsetHeight = this.obj.offsetHeight

	for (var l in this.labels) {
		if (typeof this.labels[l] != "function") {
			var labelText = this.labels[l]
			var lbox = document.createElement("div")
			lbox.style.position = "absolute"
			lbox.style.fontSize = "10pt"
			lbox.style.textAlign = "center"
			lbox.style.left = offsetLeft + (l * widthFactor) + "px"
			lbox.style.height = "1.2em"
			lbox.style.width = boxWidth + "px"
			lbox.style.top = (offsetTop + offsetHeight) + "px"
			lbox.style.overflow = "hidden"
			lbox.appendChild(document.createTextNode(labelText))
			this.obj.appendChild(lbox)
		}
	}
}
Graph.prototype.showSeriesLabels = showSeriesLabels

function addLabels(labels) {
	this.labels = labels
}
Graph.prototype.addLabels = addLabels

function drawFloatingBoxPlot(color,seriesIds,transformX,transformY) {
	transformX = (transformX) ? transformX : this.noTransformX
	transformY = (transformY) ? transformY : this.noTransformY
	
	color = (color) ? color : "blue"
	var plotSeries = new Array()
	seriesIds = (seriesIds) ? seriesIds : [0,1]
	for (var i in seriesIds) {
		if (typeof seriesIds[i] != "function")
			plotSeries.push(this.series[seriesIds[i]].clone(true))
	}
	if (plotSeries.length!=2) {
		var box = document.createElement("div")
		box.appendChild(document.createTextNode("Box Plot can only be used with TWO serieses"))
		this.obj.appendChild(box)
		return
	}
	//alert(plotSeries[1])
	this.count = this.countPoints()
	//alert(plotSeries.columnAdd().rowMax()[0][0])
	this.max = transformY(this.series.columnMax().rowMax()[0][0])
	//this.max = Math.max(this.max,this.maxValue(false,transformX,transformY))
	//alert(this.max)
	//this.min = this.minValue(false,transformX,transformY)
	this.min = transformY(this.series.columnMin().rowMin()[0][0])
	//alert(this.min)
	var heightFactor = this.obj.offsetHeight / this.max
	var widthFactor = this.obj.offsetWidth / this.count
	var boxWidth = widthFactor * 0.8
	var boxLeftPadding = (widthFactor - boxWidth)/2
	
	var offsetTop = this.obj.offsetTop 
	var offsetLeft = this.obj.offsetLeft
	var pt = this.obj.offsetParent
	while (pt) {
		offsetTop += pt.offsetTop
		offsetLeft += pt.offsetLeft
		pt = pt.offsetParent
	}
	var offsetHeight = this.obj.offsetHeight
	
	for (var i = 0;i<this.count;i++) {
		var s = 0
		var series = plotSeries[s]
		if (series.length>i) {
			//var height = series[transformX(i)] * heightFactor
			//var bottom = offsetHeight - height - (heightFactor * transformY(plotSeries[s+1][transformX(i)]))
			//var box = document.createElement("div")
			//box.style.position = "absolute"
			//box.style.left = boxLeftPadding + offsetLeft + (transformX(i) * widthFactor) + "px"
			//box.style.height = height + "px"
			//box.style.width = boxWidth + "px"
			//box.style.top = (offsetTop + bottom) + "px"
			//box.style.background = color
			//this.obj.appendChild(box)
			var bottom = transformY(series[transformX(i)])
			//alert(transformY(series[transformX(i)]) + " * " + heightFactor + " = " + bottom)
			var top = transformY(plotSeries[s+1][transformX(i)])
			//alert (bottom + " " + top)
			var height = (top - bottom) * heightFactor
			bottom = bottom * heightFactor
			top = top * heightFactor
			var box = document.createElement("div")
			box.style.position = "absolute"
			box.style.left = boxLeftPadding + offsetLeft + (transformX(i) * widthFactor) + "px"
			box.style.height = height + "px"
			box.style.width = boxWidth + "px"
			box.style.top = (offsetTop + offsetHeight - top) + "px"
			box.style.backgroundColor = color
			box.className="plotBox"
			this.obj.appendChild(box)
		}	
	}
	
	//this.max = this.maxValue(true,transformX,transformY)
}
Graph.prototype.drawFloatingBoxPlot = drawFloatingBoxPlot

function drawFunction(color,func,x1,x2,xStep,lineWidth,transformX,transformY) {
	lineWidth = (lineWidth) ? lineWidth : 2
	transformX = (transformX) ? transformX : this.noTransformX
	transformY = (transformY) ? transformY : this.noTransformY
	
	color = (color) ? color : "blue"
	var count = (x2-x1)/xStep
	var heightFactor = this.obj.offsetHeight / this.max
	var widthFactor = this.obj.offsetWidth / this.count
	var boxWidth = widthFactor
	
	var offsetTop = this.obj.offsetTop 
	var offsetLeft = this.obj.offsetLeft
	var pt = this.obj.offsetParent
	while (pt) {
		offsetTop += pt.offsetTop
		offsetLeft += pt.offsetLeft
		pt = pt.offsetParent
	}
	var offsetHeight = this.obj.offsetHeight
	
	for (var i = x1;i<=x2;i++) {
		var height = transformY(func(transformX(i))) * heightFactor
		//alert(height)
		var bottom = height + lineWidth
		var box = document.createElement("div")
		box.style.position = "absolute"
		box.style.left = offsetLeft + (transformX(i) * widthFactor) + "px"
		box.style.height = lineWidth + "px"
		box.style.width = boxWidth + "px"
		box.style.top = (offsetTop + bottom) + "px"
		box.style.backgroundColor = color
		this.obj.appendChild(box)
	}
}
Graph.prototype.drawFunction = drawFunction

var g1 = null
function graphTest() {
	if (!g1) {
		var gb = document.createElement("div")
		gb.id = "graphBorder"
		var g = document.createElement("div")
		g.id = "graph"
		g = gb.appendChild(g)
		document.body.appendChild(gb)
		g1 = new Graph(g)
	}
	g1.clearSeries()
	g1.addLabels(["A1","A2","A3","B1","B2","B3","C1","C2","C3"])
	var s1 = g1.addSeries([100,200,300,400,500,600,700,800,400])
	var s2 = g1.addSeries([100,200,300,400,500,600,700,800,400])
	var s3 = g1.addSeries([100,200,200,100,200,200,100,400,200])
	g1.drawBoxPlot("green",s1)
	g1.drawFloatingBoxPlot("blue",[s2,s3])
	g1.showSeriesLabels()
}